/*  -------------------------- (C) COPYRIGHT 2022 Fortiortech ShenZhen ---------------------------*/
/**
 * @copyright (C) COPYRIGHT 2022 Fortiortech Shenzhen
 * @file
 * @author    Fortiortech  Appliction Team
 * @since     Create:2022-07-14
 * @date      Last modify:2022-07-14
 * @note      Last modify author is Leo.li
 * @brief
 */

/* Includes ------------------------------------------------------------------*/
#include <FU68xx_2.h>
#include <Myproject.h>

ROM_TypeDef xdata  FlashData;

uint8 Flash_GetAddress(void);


/**
 * @brief        读取固定地址值
 * @date         2022-07-14
 */
uint8 ReadFlashValue(uint16 ReadAddress)
{
    uint16 TempAddress0 = ReadAddress;
    __IO uint8 tevalue = 0;        //临时变量
    tevalue = *(uint8 code *)TempAddress0;   //读取回地址的值
    return tevalue;
}

/**
 * @brief        擦除指定扇区
 * @brief        FlashAddress--Flash自擦除扇区内任意地址
 * @return       0--Flash自擦除成功，1--Flash自擦除失败
 * @date         2022-07-14
 */
uint8 Flash_Sector_Erase(uint8 xdata * FlashAddress)
{
    bool TempEA;
    uint16 TempFlashAddress;
    TempEA = EA;
    EA = 0;
    TempFlashAddress = FlashAddress;
    
    if ((TempFlashAddress) < (0x3f80))        // 不擦除最后一个扇区
    {
        FLA_CR = 0x03;                        //使能自擦除
        FLA_KEY = 0x5a;
        FLA_KEY = 0x1f;                       //flash预编程解锁
        _nop_();
        *FlashAddress = 0xff;                 //写任意数据
        FLA_CR = 0x08;                        //开始预编程，完成后Flash再次上锁
    }
    
    EA = TempEA;
    
    if (ReadBit(FLA_CR, FLAERR))
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

/**
 * @brief        擦除指定扇区
 * @brief        FlashAddress--指定写入地址
 * @brief        FlashData--写入数值
 * @return       0--Flash自擦除成功，1--Flash自擦除失败
 * @date         2022-07-14
 */
void Flash_Sector_Write(uint8 xdata * FlashAddress, uint8 Flash_Data)
{
    bool TempEA = 0;
    uint16 TempFlashAddress;
    TempEA = EA;
    EA = 0;
    TempFlashAddress = FlashAddress;
    
    if ((TempFlashAddress) < 0x3f80)        // 不编程最后一个扇区
    {
        FLA_CR = 0x01;              // 使能Flash编程
        FLA_KEY = 0x5a;
        FLA_KEY = 0x1f;             // flash预编程解锁
        _nop_();
        *FlashAddress = Flash_Data;  // 写编程数据
        FLA_CR = 0x08;              // 开始预编程，完成后Flash再次上锁
    }
    
    EA = TempEA;
}

/**
 * @brief        WriteAddress--指定写入地址
 * @brief        Length：写入数组长度
 * @brief        value--写入数组
 * @date         2022-11-14
 */
uint8 Flash_WriteValue(uint16 WriteAddress, uint8 Length, uint8 * str)
{
    uint8 i;
    uint8 TempReadRomValue;
    uint16 FlashWriteAddr = WriteAddress;
    
    //读出有效数据
    for (i = 0; i < Length; i++)
    {
        Flash_Sector_Write(FlashWriteAddr + i, str[i]);
        TempReadRomValue = *(uint8 code *)(FlashWriteAddr + i);
        
        if (TempReadRomValue != str[i])
        {
            return 0;
        }
    }
    
    return 1;
}


/**
* @brief        获取最后写入的地址，确认最新能写入的地址
* @brief        unsigned short FlashAddress：目标FLASH首地址
* @brief        uint8 Write_Length：写入数值长度
*/
uint16 GetWrite_Black_Addr(unsigned short FlashAddress, uint8 Write_Length)
{
    uint16 TempFlashAddress = 0;
    uint16 TempFirstAddress = 0;             //用来保存保存首地址
    uint8  tempFlashData = 0xFF;
    uint8  Length = 0;
    TempFlashAddress = FlashAddress;
    TempFirstAddress = FlashAddress;
    
    while ((Length != Write_Length) && (TempFlashAddress < (TempFirstAddress + Write_Length))) //限定读取地址为当前页
    {
        tempFlashData = *(uint8 code *)(TempFlashAddress);  //读取目标地址中数值是否为0
        
        if (tempFlashData == 0)
        {
            Length ++;
            TempFlashAddress  += 1;
        }
        else
        {
            TempFirstAddress  += Write_Length;        //首地址跳转Write_Length字节
            
            if (TempFirstAddress > 0x3f80)
            {
                TempFirstAddress  = 0x3f80;
            }
            
            TempFlashAddress  = TempFirstAddress;
            Length = 0;
        }
    }
    
    return TempFirstAddress;
}


/**
 * @brief        读取Length字节数据，
 * @Input        unsigned short BlockStartAddr：目标FLASH首地址
 * @Input        uint8 Length：数值长度
 * @Input        uint8 * str ：读回数值写入数组
 * @ruturn       Flash数据
 */
void ReadFromFlash(unsigned short BlockStartAddr, uint8 Length, uint8 * str)
{
    uint8 i = 0;
    
    for (i = 0; i < Length; i++)
    {
        str[i] = *(uint8 code *)(BlockStartAddr + i);
    }
}

/**
 * @brief        扇区擦除
 * @Input
 * @ruturn
 */
void Flash_Erase(void)
{
    uint8 FlashEraseStatus = 0;
    FlashEraseStatus = Flash_Sector_Erase(START_WriteADDRESS);
    
    if (!FlashEraseStatus)
    {
        /*----- 获取写入首地址 -----*/
        FlashData.WriteAddress = GetWrite_Black_Addr(START_WriteADDRESS, Write_Lenght);
    }
    else
    {
        FlashEraseStatus = Flash_Sector_Erase(START_WriteADDRESS);
        FlashData.WriteAddress = START_WriteADDRESS;                     //第一次擦写失败后第二次擦写，强行给地址
        
        /*----- 第二次擦写再失败，默认为Flash损坏，不进行处理 -----*/
        if (FlashEraseStatus)
        {
            ;
        }
    }
    
    FlashData.Flag_FlashErase = 0;
}


/**
 * @brief        保存按键
 * @date         2022-11-14
 */
void  Save_KeyValue(void)
{
    uint8 FlashWriteStatus = 0;        //返回值
    uint8 TempReadValue = 0;
    FlashData.WriteValue[0] = KS.KeyValuetotal;
    
    if (FlashData.ReadValue[0] != FlashData.WriteValue[0]) //确认写入前后数据不一致
    {
        EA = 0;
        
        while (!FlashWriteStatus)   //写入异常，换到下个地址写入
        {
            FlashWriteStatus = Flash_WriteValue(FlashData.WriteAddress, Write_Lenght, FlashData.WriteValue);
            
            if (FlashWriteStatus)
            {
                Flash_Sector_Write(FlashData.WriteAddress + Verify_Bit, Verify_Ture);
                TempReadValue = *(uint8 code *)(FlashData.WriteAddress + Verify_Bit);
                /*----- 更新读取Flash首地址 -----*/
                FlashData.ReadAddress = FlashData.WriteAddress - Write_Lenght;
                /*----- 读取数值到FlashData.ReadValue -----*/
                ReadFromFlash(FlashData.ReadAddress, Write_Lenght, FlashData.ReadValue);
                
                if (TempReadValue == Verify_Ture)
                {
                    goto exit;
                }
                else
                {
                    FlashWriteStatus = 0;
                }
            }
            else
            {
                Flash_Sector_Write(FlashData.WriteAddress + Verify_Bit, Verify_Error);
                FlashData.WriteAddress = FlashData.WriteAddress + Write_Lenght;
                
                if (FlashData.WriteAddress > START_WriteADDRESS + 0x70)
                {
                    FlashData.Flag_FlashErase = 1;      //写到扇区最后字节，依然失败，直接进行数值清楚
                    goto exit;
                }
            }
        }
        
    exit:
        EA = 1;
    }
}

